import numpy as np
import pandas as pd
import logging
from datetime import datetime, time, timedelta
import colorama  # 用于彩色输出
from colorama import Fore, Style
from django.db import connection

# 初始化colorama
colorama.init()

logger = logging.getLogger(__name__)

class BasalRateAdjustment:
    """
    自适应基础率控制器，根据血糖监测调整基础率
    
    该控制器根据不同时间点的血糖值比较来调整基础率：
    1. 夜间调整规则：
       - 睡前和晚餐后2小时比较
       - 凌晨3:00和睡前比较
       - 早餐前和凌晨3:00比较
       - 如果差值大于1.7 mmol/L，调整基础率10%-20%
    
    2. 日间调整规则：
       - 对比餐后2小时血糖和下餐前血糖水平
       - 如果血糖下降超过3.3mmol/L或血糖降至3.9mmol/L以下，减少10%-20%基础率
       - 如果血糖不能下降或下降小于1.7mmol/L，增加10%-20%基础率
    """
    def __init__(self, patient_number):
        """初始化控制器"""
        self.patient_number = patient_number
        print(f"\n{Fore.BLUE}===== 开始基础率调整计算 [{patient_number}] ====={Style.RESET_ALL}")
        
        # 默认餐点时间，如果数据库中没有记录则使用这些默认值
        self.default_meal_times = {
            "早餐": time(7, 0),  # 早餐时间
            "午餐": time(12, 0),  # 午餐时间
            "晚餐": time(18, 0)   # 晚餐时间
        }
        
        # 获取患者餐食时间
        self.meal_times = self._get_patient_meal_times()
        
        # 动态生成时间段
        self._generate_time_periods()
        
        # 初始化基础率调整字典
        self.basal_adjustments = {period: 1.0 for period in self.time_periods.keys()}
        self.adjustment_reasons = {}
        
        # 血糖值阈值（mmol/L）
        self.hypoglycemia_threshold = 3.9  # 低血糖阈值
        self.delta_threshold_min = 1.7  # 最小血糖差值阈值
        self.delta_threshold_max = 3.3  # 最大血糖差值阈值
        
        # 基础率调整范围
        self.min_adjustment = 0.1  # 最小调整幅度 (10%)
        self.max_adjustment = 0.2  # 最大调整幅度 (20%)
        
        # 获取TDI和基础率数据
        self.base_basal_rate = self._get_patient_basal_data()
        print(f"{Fore.CYAN}基础胰岛素率: {self.base_basal_rate * 60:.3f} U/hour{Style.RESET_ALL}")
        print(f"{Fore.CYAN}调整决策阈值: 最小差值阈值 {self.delta_threshold_min} mmol/L, 最大差值阈值 {self.delta_threshold_max} mmol/L{Style.RESET_ALL}")
        print(f"{Fore.CYAN}低血糖阈值: {self.hypoglycemia_threshold} mmol/L{Style.RESET_ALL}")
        
    def _generate_time_periods(self, date_for_periods=None):
        """动态生成基于患者实际餐食时间的时间段"""
        print(f"\n{Fore.YELLOW}生成患者时间段划分...{Style.RESET_ALL}")
        
        # 如果传入了特定日期，则餐食时间也应基于该日期获取或使用最新的
        # 注意：self.meal_times 此处可能已经是特定日期的，也可能是最新的
        # 为了清晰，可以再次调用 _get_patient_meal_times 如果 date_for_periods 不同于初始化时的隐含日期
        # 但当前设计是 self.meal_times 在 generate_basal_recommendations 中被更新

        breakfast_time = self.meal_times.get("早餐")
        lunch_time = self.meal_times.get("午餐")
        dinner_time = self.meal_times.get("晚餐")
        
        # 用于时间计算的日期，优先使用传入的 date_for_periods
        base_date = date_for_periods if date_for_periods else datetime.now().date()
        
        # 动态计算各个时间点
        breakfast_2h = (datetime.combine(base_date, breakfast_time) + timedelta(hours=2)).time()
        lunch_2h = (datetime.combine(base_date, lunch_time) + timedelta(hours=2)).time()
        dinner_2h = (datetime.combine(base_date, dinner_time) + timedelta(hours=2)).time()
        
        # 动态生成时间段
        self.time_periods = {
            # 夜间时间段
            "00:00-03:00": {"start": time(0, 0), "end": time(3, 0), "name": "凌晨"},
            # 早晨时间段：从凌晨3点到实际早餐时间
            f"03:00-{breakfast_time.strftime('%H:%M')}": {"start": time(3, 0), "end": breakfast_time, "name": "早晨"},
            
            # 白天时间段 - 基于实际餐点时间动态划分
            f"{breakfast_time.strftime('%H:%M')}-{breakfast_2h.strftime('%H:%M')}": {
                "start": breakfast_time, 
                "end": breakfast_2h, 
                "name": "早餐到早餐后"
            },
            f"{breakfast_2h.strftime('%H:%M')}-{lunch_time.strftime('%H:%M')}": {
                "start": breakfast_2h, 
                "end": lunch_time, 
                "name": "早餐后到午餐前"
            },
            f"{lunch_time.strftime('%H:%M')}-{lunch_2h.strftime('%H:%M')}": {
                "start": lunch_time, 
                "end": lunch_2h, 
                "name": "午餐到午餐后"
            },
            f"{lunch_2h.strftime('%H:%M')}-{dinner_time.strftime('%H:%M')}": {
                "start": lunch_2h, 
                "end": dinner_time, 
                "name": "午餐后到晚餐前"
            },
            f"{dinner_time.strftime('%H:%M')}-{dinner_2h.strftime('%H:%M')}": {
                "start": dinner_time, 
                "end": dinner_2h, 
                "name": "晚餐到晚餐后"
            },
            f"{dinner_2h.strftime('%H:%M')}-00:00": {
                "start": dinner_2h, 
                "end": time(0, 0), 
                "name": "晚餐后到睡前"
            },
        }
        
        # 打印时间段划分
        print(f"{Fore.GREEN}患者时间段划分如下:{Style.RESET_ALL}")
        for period, info in self.time_periods.items():
            print(f"  • {period} - {info['name']}")
    
    def _get_patient_meal_times(self, query_date=None):
        """从数据库获取患者餐食时间。
        优先使用 query_date 当天的记录。
        如果当天无记录，则尝试 query_date 前一天的记录。
        如果前一天也无记录，则使用默认时间。
        """
        final_meal_times = self.default_meal_times.copy() # 从默认值开始
        # meal_source_log = {meal: f"{time_val.strftime('%H:%M')} (默认值)" for meal, time_val in self.default_meal_times.items()}
        meal_source_log = {}

        dates_to_check = []
        if query_date:
            dates_to_check.append(query_date)             # 检查目标日期
            dates_to_check.append(query_date - timedelta(days=1)) # 然后检查前一天
            current_process_date_info = query_date.strftime('%Y-%m-%d')
        else:
            # 如果没有 query_date (例如初始化时)，只获取最新的，或依赖默认值
            # 这种情况下，我们可能不需要回退逻辑，或者回退到昨天（相对于 now()）
            # 为简化，此处若无 query_date，则行为与之前获取"最新"类似，但不进行特定日期回退
            current_process_date_info = "最新/默认"
            # dates_to_check.append(datetime.now().date()) # 可选：检查今天
            # dates_to_check.append(datetime.now().date() - timedelta(days=1)) # 可选：检查昨天

        print(f"{Fore.YELLOW}正在为患者 {self.patient_number} 获取餐食时间 (目标基准日期: {current_process_date_info})...{Style.RESET_ALL}")

        # 先获取该患者所有餐食记录，以便后续筛选
        all_patient_meals_sorted = []
        try:
            with connection.cursor() as cursor:
                query = """
                    SELECT meal_type, time 
                    FROM patient_meal
                    WHERE patient_number = %s
                    ORDER BY time DESC 
                """
                cursor.execute(query, [self.patient_number])
                all_patient_meals_sorted = cursor.fetchall()
        except Exception as e:
            print(f"{Fore.RED}数据库查询餐食记录时出错: {e}{Style.RESET_ALL}")
            # 出错则全部使用默认值，meal_source_log 会在后面正确反映

        # 核心三餐，我们将优先查找这些
        main_meals = ["早餐", "午餐", "晚餐"]

        if query_date: # 只有在指定查询日期时，才应用这个详细的回退逻辑
            for meal_type in main_meals:
                found_for_meal = False
                for date_to_check_idx, date_val in enumerate(dates_to_check):
                    # 在已获取的所有记录中查找特定日期和特定餐别
                    for db_meal_type, db_meal_datetime in all_patient_meals_sorted:
                        if db_meal_type == meal_type and db_meal_datetime.date() == date_val:
                            final_meal_times[meal_type] = db_meal_datetime.time()
                            date_source_str = "目标日" if date_to_check_idx == 0 else "前一日"
                            meal_source_log[meal_type] = f"{db_meal_datetime.time().strftime('%H:%M')} (来自{date_source_str} {date_val.strftime('%Y-%m-%d')})"
                            found_for_meal = True
                            break # 找到该餐该日期的最新一条就跳出内层循环
                    if found_for_meal:
                        break # 已为当前 meal_type 找到时间，跳出日期检查循环
                
                if not found_for_meal:
                    meal_source_log[meal_type] = f"{final_meal_times[meal_type].strftime('%H:%M')} ({Fore.YELLOW}默认值{Style.RESET_ALL})"
        else:
            # 如果没有 query_date，则采用之前的"获取最新"逻辑
            latest_overall_meals = {}
            for db_meal_type, db_meal_datetime in all_patient_meals_sorted:
                if db_meal_type not in latest_overall_meals: # 只取该餐类的最新一条
                    latest_overall_meals[db_meal_type] = db_meal_datetime.time()
            
            for meal_type in main_meals:
                if meal_type in latest_overall_meals:
                    final_meal_times[meal_type] = latest_overall_meals[meal_type]
                    meal_source_log[meal_type] = f"{latest_overall_meals[meal_type].strftime('%H:%M')} (来自最新记录)"
                else:
                    meal_source_log[meal_type] = f"{final_meal_times[meal_type].strftime('%H:%M')} ({Fore.YELLOW}默认值{Style.RESET_ALL})"

        # 打印最终使用的餐食时间及其来源
        print(f"{Fore.CYAN}最终使用的餐食时间 (基于 {current_process_date_info}):{Style.RESET_ALL}")
        for meal_type in main_meals:
            # meal_source_log.get(meal_type) 应该总是有值的
            log_entry = meal_source_log.get(meal_type, f"{final_meal_times[meal_type].strftime('%H:%M')} ({Fore.RED}未知来源{Style.RESET_ALL})")
            print(f"  • {meal_type}: {log_entry}")
        
        # 对于非核心餐次（如果以后有的话），可以简单地使用最新或默认
        # 此处我们只关心三餐，所以 final_meal_times 中非三餐的时间如果被更新了，也保留

        return final_meal_times
    
    def _get_patient_basal_data(self):
        """从数据库获取患者的基础胰岛素相关数据"""
        try:
            print(f"{Fore.YELLOW}正在获取患者 {self.patient_number} 的基础胰岛素数据...{Style.RESET_ALL}")
            with connection.cursor() as cursor:
                query = """
                    SELECT tdd, basal_insulin 
                    FROM patient_info
                    WHERE patient_number = %s
                """
                cursor.execute(query, [self.patient_number])
                result = cursor.fetchone()
                
                if result:
                    tdd, basal_insulin = result
                    
                    # 如果数据库中已经有基础胰岛素值，则直接使用
                    if basal_insulin is not None:
                        print(f"  • 从数据库获取到基础胰岛素: {basal_insulin} U/day")
                        return basal_insulin / (24 * 60)  # 转换为U/min
                    
                    # 否则，如果有TDI，根据TDI计算基础率
                    elif tdd is not None:
                        basal_value = (tdd * 0.5)
                        print(f"  • 基于TDD计算基础胰岛素: {tdd} * 0.5 = {basal_value} U/day")
                        return basal_value / (24 * 60)  # 基础率是TDI的50%除以24小时
                    
                # 如果没有数据，使用默认值
                print(f"{Fore.YELLOW}  • 未找到基础胰岛素数据，使用默认值: 0.5 U/day{Style.RESET_ALL}")
                return 0.5 / (24 * 60)  # 默认TDI为24U/day的50%
        except Exception as e:
            print(f"{Fore.RED}获取患者基础数据出错: {e}{Style.RESET_ALL}")
            print(f"{Fore.YELLOW}使用默认基础胰岛素值: 0.5 U/day{Style.RESET_ALL}")
            return 0.5 / (24 * 60)  # 出错时使用默认值
    
    def _mg_dl_to_mmol_l(self, mg_dl):
        """将血糖单位从mg/dL转换为mmol/L"""
        return mg_dl / 18.0
    
    def _get_cgm_at_time(self, target_hour, target_minute=0, date=None):
        """
        获取特定时间点最接近的血糖值
        
        参数：
        target_hour: 目标小时
        target_minute: 目标分钟
        date: 指定日期，如果为None则使用当天
        
        返回：
        最接近的血糖值（mmol/L）或None
        """
        table_name = f'cgm_{self.patient_number}'
        target_time = f"{target_hour:02d}:{target_minute:02d}"
        
        try:
            with connection.cursor() as cursor:
                if date:
                    # 使用指定日期
                    start_time = datetime.combine(date, time(target_hour, target_minute)) - timedelta(minutes=30)
                    end_time = datetime.combine(date, time(target_hour, target_minute)) + timedelta(minutes=30)
                else:
                    # 使用当天日期
                    today = datetime.now().date()
                    start_time = datetime.combine(today, time(target_hour, target_minute)) - timedelta(minutes=30)
                    end_time = datetime.combine(today, time(target_hour, target_minute)) + timedelta(minutes=30)
                
                # 目标时间点
                target_datetime = datetime.combine(start_time.date(), time(target_hour, target_minute))
                
                # 简化查询，不使用时间差排序，直接查找时间段内的第一条记录
                try:
                    # 将表名与SQL语句直接拼接，参数通过列表传递
                    query = f"""
                        SELECT sgv, sg_date
                        FROM {table_name}
                        WHERE sg_date BETWEEN %s AND %s
                        ORDER BY sg_date
                        LIMIT 1
                    """
                    cursor.execute(query, [start_time, end_time])
                    
                    result = cursor.fetchone()
                    
                    if result:
                        sgv, sg_date = result
                        mmol_value = self._mg_dl_to_mmol_l(sgv)
                        print(f"  • 时间点 {target_time} 血糖值: {mmol_value:.2f} mmol/L (原始: {sgv} mg/dL, 实际时间: {sg_date.strftime('%H:%M')})")
                        return mmol_value
                    else:
                        print(f"{Fore.YELLOW}  • 时间点 {target_time} 无血糖数据{Style.RESET_ALL}")
                        return None
                except Exception as query_error:
                    print(f"{Fore.RED}  • 查询时间点 {target_time} 出错: {query_error}{Style.RESET_ALL}")
                    return None
        except Exception as e:
            print(f"{Fore.RED}获取时间点 {target_time} 的血糖数据出错: {e}{Style.RESET_ALL}")
            return None
    
    def _fetch_cgm_data_by_day(self, date):
        """获取指定日期的所有CGM数据"""
        table_name = f'cgm_{self.patient_number}'
        
        try:
            with connection.cursor() as cursor:
                start_time = datetime.combine(date, time(0, 0))
                end_time = datetime.combine(date, time(23, 59, 59))
                
                # 将表名与SQL语句直接拼接，参数通过列表传递
                query = f'''
                    SELECT sg_date, sgv
                    FROM {table_name}
                    WHERE sg_date BETWEEN %s AND %s
                    ORDER BY sg_date ASC
                '''
                cursor.execute(query, [start_time, end_time])
                
                results = cursor.fetchall()
                return [(item[0], item[1]) for item in results]
        except Exception as e:
            print(f"{Fore.RED}获取日期 {date} 的CGM数据出错: {e}{Style.RESET_ALL}")
            return []
    
    def _adjust_basal_rate(self, date=None):
        """根据不同时间点的血糖值比较来调整基础率，关键在于使用昨天的血糖数据"""
        print(f"\n{Fore.MAGENTA}===== 夜间基础率调整判断 ====={Style.RESET_ALL}")

        # 确定用于获取血糖数据的日期，如果提供了date (今天)，则血糖数据应来自昨天
        cgm_query_date = date - timedelta(days=1) if date else None
        if date:
            print(f"{Fore.YELLOW}计算 {date.strftime('%Y-%m-%d')} 的建议，将使用 {cgm_query_date.strftime('%Y-%m-%d')} 的血糖数据。{Style.RESET_ALL}")


        # 获取餐点时间 (注意：这里获取的是最新的餐点时间，理想情况下应获取 'date' 当天的计划餐点时间)
        breakfast_time = self.meal_times.get("早餐")
        lunch_time = self.meal_times.get("午餐")
        dinner_time = self.meal_times.get("晚餐")
        
        # 今天日期，用于时间计算
        evaluation_date = date if date else datetime.now().date() # 用于生成时间点，基于传入的date
        
        # 动态计算各个时间点
        dinner_2h_dt = (datetime.combine(evaluation_date, dinner_time) + timedelta(hours=2))
        bedtime_dt = datetime.combine(evaluation_date, time(22, 0)) # 假设睡前为22:00
        dawn_3am_dt = datetime.combine(evaluation_date, time(3, 0))
        before_breakfast_dt = datetime.combine(evaluation_date, breakfast_time)
        
        breakfast_2h_dt = (datetime.combine(evaluation_date, breakfast_time) + timedelta(hours=2))
        before_lunch_dt = datetime.combine(evaluation_date, lunch_time)
        lunch_2h_dt = (datetime.combine(evaluation_date, lunch_time) + timedelta(hours=2))
        before_dinner_dt = datetime.combine(evaluation_date, dinner_time)

        # 1. 睡前和晚餐后2小时比较
        print(f"\n{Fore.CYAN}1. 睡前和晚餐后2小时比较 (适用时段: {dinner_2h_dt.strftime('%H:%M')}-{bedtime_dt.strftime('%H:%M')}){Style.RESET_ALL}")
        dinner_2h_sg = self._get_cgm_at_time(dinner_2h_dt.hour, dinner_2h_dt.minute, date=cgm_query_date)
        bedtime_sg = self._get_cgm_at_time(bedtime_dt.hour, bedtime_dt.minute, date=cgm_query_date)
        self._evaluate_adjustment(
            sg1_val=dinner_2h_sg, sg1_name=f"晚餐后2小时({dinner_2h_dt.strftime('%H:%M')})",
            sg2_val=bedtime_sg, sg2_name=f"睡前({bedtime_dt.strftime('%H:%M')})",
            period_key=f"{dinner_2h_dt.strftime('%H:%M')}-00:00" # 使用动态生成的key
        )

        # 2. 凌晨3:00和睡前比较
        print(f"\n{Fore.CYAN}2. 凌晨3:00和睡前比较 (适用时段: 00:00-03:00){Style.RESET_ALL}")
        dawn_3am_sg = self._get_cgm_at_time(dawn_3am_dt.hour, dawn_3am_dt.minute, date=cgm_query_date)
        # bedtime_sg 已获取
        self._evaluate_adjustment(
            sg1_val=bedtime_sg, sg1_name=f"睡前({bedtime_dt.strftime('%H:%M')})",
            sg2_val=dawn_3am_sg, sg2_name=f"凌晨3:00({dawn_3am_dt.strftime('%H:%M')})",
            period_key="00:00-03:00"
        )

        # 3. 早餐前和凌晨3:00比较
        morning_period_key = f"03:00-{breakfast_time.strftime('%H:%M')}"
        print(f"\n{Fore.CYAN}3. 早餐前和凌晨3:00比较 (适用时段: {morning_period_key}){Style.RESET_ALL}")
        before_breakfast_sg = self._get_cgm_at_time(before_breakfast_dt.hour, before_breakfast_dt.minute, date=cgm_query_date)
        # dawn_3am_sg 已获取
        self._evaluate_adjustment(
            sg1_val=dawn_3am_sg, sg1_name=f"凌晨3:00({dawn_3am_dt.strftime('%H:%M')})",
            sg2_val=before_breakfast_sg, sg2_name=f"早餐前({before_breakfast_dt.strftime('%H:%M')})",
            period_key=morning_period_key
        )
        
        print(f"\n{Fore.MAGENTA}===== 日间基础率调整判断 ====={Style.RESET_ALL}")

        # 4. 早餐后到午餐前时段
        period_key_bf_lunch = f"{breakfast_2h_dt.strftime('%H:%M')}-{before_lunch_dt.strftime('%H:%M')}"
        print(f"\n{Fore.CYAN}4. 早餐后到午餐前时段 (适用时段: {period_key_bf_lunch}){Style.RESET_ALL}")
        breakfast_2h_sg = self._get_cgm_at_time(breakfast_2h_dt.hour, breakfast_2h_dt.minute, date=cgm_query_date)
        before_lunch_sg = self._get_cgm_at_time(before_lunch_dt.hour, before_lunch_dt.minute, date=cgm_query_date)
        self._evaluate_adjustment_daytime(
            sg_after_meal_val=breakfast_2h_sg, sg_after_meal_name=f"早餐后2小时({breakfast_2h_dt.strftime('%H:%M')})",
            sg_before_next_meal_val=before_lunch_sg, sg_before_next_meal_name=f"午餐前({before_lunch_dt.strftime('%H:%M')})",
            period_key=period_key_bf_lunch
        )

        # 5. 午餐后到晚餐前时段
        period_key_lunch_dinner = f"{lunch_2h_dt.strftime('%H:%M')}-{before_dinner_dt.strftime('%H:%M')}"
        print(f"\n{Fore.CYAN}5. 午餐后到晚餐前时段 (适用时段: {period_key_lunch_dinner}){Style.RESET_ALL}")
        lunch_2h_sg = self._get_cgm_at_time(lunch_2h_dt.hour, lunch_2h_dt.minute, date=cgm_query_date)
        before_dinner_sg = self._get_cgm_at_time(before_dinner_dt.hour, before_dinner_dt.minute, date=cgm_query_date)
        self._evaluate_adjustment_daytime(
            sg_after_meal_val=lunch_2h_sg, sg_after_meal_name=f"午餐后2小时({lunch_2h_dt.strftime('%H:%M')})",
            sg_before_next_meal_val=before_dinner_sg, sg_before_next_meal_name=f"晚餐前({before_dinner_dt.strftime('%H:%M')})",
            period_key=period_key_lunch_dinner
        )
        
        # 标记未调整的时段
        print(f"\n{Fore.YELLOW}以下时段未进行调整判断或未触发调整条件:{Style.RESET_ALL}")
        all_periods = set(self.time_periods.keys())
        adjusted_periods = set(self.adjustment_reasons.keys())
        unadjusted_periods = all_periods - adjusted_periods
        for period in unadjusted_periods:
            print(f"  • {period} ({self.time_periods[period]['name']})")
        
        return self.basal_adjustments, self.adjustment_reasons
    
    def generate_basal_recommendations(self, date=None):
        """
        生成基础率调整建议
        
        参数：
        date: 指定建议应用的目标日期，如果为None则使用当天。
              分析将基于该日期的前一天的数据。
        
        返回：
        包含时间段、调整百分比、调整方向和调整原因的列表
        """
        print(f"\n{Fore.BLUE}===== 生成基础率调整建议 ====={Style.RESET_ALL}")
        
        # 确定数据分析日期（目标日期的前一天）
        analysis_date = (date - timedelta(days=1)) if date else (datetime.now().date() - timedelta(days=1))
        target_recommendation_date = date if date else datetime.now().date()

        print(f"{Fore.CYAN}为目标日期 {target_recommendation_date.strftime('%Y-%m-%d')} 生成建议，将分析日期 {analysis_date.strftime('%Y-%m-%d')} 的数据。{Style.RESET_ALL}")

        # 获取分析日期（昨天）的餐食时间并生成相应的时间段
        print(f"{Fore.CYAN}获取分析日期 {analysis_date.strftime('%Y-%m-%d')} 的餐食时间和生成时间段...{Style.RESET_ALL}")
        self.meal_times = self._get_patient_meal_times(query_date=analysis_date)
        self._generate_time_periods(date_for_periods=analysis_date) 
        
        # 重新初始化调整字典以匹配新的时间段
        self.basal_adjustments = {period: 1.0 for period in self.time_periods.keys()}
        self.adjustment_reasons = {} # 清空旧的原因

        # _adjust_basal_rate 调用时传入的是目标建议日期，
        # 但其内部获取CGM数据时会使用 (目标日期 - 1天)，即 analysis_date
        # 餐食时间点 (breakfast_time等) 和 时间段 (self.time_periods) 已基于 analysis_date 设置
        adjustments, adjustment_reasons = self._adjust_basal_rate(target_recommendation_date)
        
        recommendations = []
        for period, factor in adjustments.items():
            # 获取时间段信息
            time_info = self.time_periods[period]
            period_name = time_info["name"]
            
            # 计算调整百分比
            adjustment_pct = (factor - 1.0) * 100
            change_direction = "增加" if adjustment_pct > 0 else "减少" if adjustment_pct < 0 else "维持"
            
            # 获取调整原因
            reason = adjustment_reasons.get(period, "无需调整") # 默认 "无需调整"

            # 特殊处理餐后2小时内的时段的默认原因
            is_post_meal_period = "到" in period_name and ("早餐后" in period_name or "午餐后" in period_name or "晚餐后" in period_name)
            # More specific check for periods like "早餐到早餐后"
            if period_name in ["早餐到早餐后", "午餐到午餐后", "晚餐到晚餐后"] and reason == "无需调整":
                reason = "餐后两小时内不调整基础胰岛素，因其主要维持全天基础血糖水平，调整需基于长期趋势而非短期餐后波动。"
            
            # 打印调整详情
            if adjustment_pct != 0:
                status_color = Fore.GREEN
            else:
                status_color = Fore.YELLOW
                
            print(f"{status_color}时段 {period} ({period_name}):")
            print(f"  调整建议: {change_direction} {abs(adjustment_pct):.1f}%")
            print(f"  调整原因: {reason}{Style.RESET_ALL}")
            
            # 添加到建议列表
            recommendations.append({
                "period": period,
                "period_name": period_name,
                "adjustment_pct": round(adjustment_pct, 1),
                "change_direction": change_direction,
                "reason": reason
            })
        
        return recommendations
    
    def save_basal_adjustment(self, period, new_factor):
        """保存基础率调整"""
        self.basal_adjustments[period] = new_factor

    def _evaluate_adjustment(self, sg1_val, sg1_name, sg2_val, sg2_name, period_key):
        """评估夜间基础率调整"""
        adjustment_made = False
        reason_description = ""

        if sg1_val is not None and sg2_val is not None:
            diff = sg2_val - sg1_val
            reason_description = f"{sg2_name}血糖({sg2_val:.2f})与{sg1_name}血糖({sg1_val:.2f})差值为{diff:.2f}mmol/L"
            print(f"   血糖差值 ({sg2_name} - {sg1_name}): {diff:.2f} mmol/L (阈值: ±{self.delta_threshold_min})")
            
            if diff > self.delta_threshold_min:  # 血糖显著上升
                reason_final = f"{reason_description}，血糖上升超过{self.delta_threshold_min}mmol/L，建议增加基础率{self.min_adjustment*100}%"
                print(f"{Fore.GREEN}   触发调整: {reason_final}{Style.RESET_ALL}")
                self.basal_adjustments[period_key] = 1.0 + self.min_adjustment
                self.adjustment_reasons[period_key] = reason_final
                adjustment_made = True
            elif diff < -self.delta_threshold_min:  # 血糖显著下降
                reason_final = f"{reason_description}，血糖下降超过{self.delta_threshold_min}mmol/L，建议减少基础率{self.max_adjustment*100}%"
                print(f"{Fore.GREEN}   触发调整: {reason_final}{Style.RESET_ALL}")
                self.basal_adjustments[period_key] = 1.0 - self.max_adjustment
                self.adjustment_reasons[period_key] = reason_final
                adjustment_made = True
            
            if not adjustment_made:
                reason_final = f"{reason_description}，血糖变化在可接受范围内，无需调整。"
                print(f"{Fore.YELLOW}   未触发调整: {reason_final}{Style.RESET_ALL}")
                self.adjustment_reasons[period_key] = reason_final # 即使未调整，也记录原因
        else:
            missing_sg1 = sg1_name if sg1_val is None else ""
            missing_sg2 = sg2_name if sg2_val is None else ""
            conjunction = "和" if missing_sg1 and missing_sg2 else ""
            reason_description = f"缺少 {missing_sg1}{conjunction}{missing_sg2} 数据，无法评估，无需调整。"
            print(f"{Fore.RED}   {reason_description}{Style.RESET_ALL}")
            self.adjustment_reasons[period_key] = reason_description # 记录数据缺失的原因

    def _evaluate_adjustment_daytime(self, sg_after_meal_val, sg_after_meal_name, sg_before_next_meal_val, sg_before_next_meal_name, period_key):
        """评估日间基础率调整"""
        adjustment_made = False
        reason_description = ""

        if sg_after_meal_val is not None and sg_before_next_meal_val is not None:
            diff = sg_before_next_meal_val - sg_after_meal_val
            reason_description = f"{sg_before_next_meal_name}血糖({sg_before_next_meal_val:.2f})与{sg_after_meal_name}血糖({sg_after_meal_val:.2f})差值为{diff:.2f}mmol/L"
            print(f"   血糖差值 ({sg_before_next_meal_name} - {sg_after_meal_name}): {diff:.2f} mmol/L")
            print(f"   {sg_before_next_meal_name}血糖: {sg_before_next_meal_val:.2f} mmol/L (低血糖阈值: <{self.hypoglycemia_threshold})")
            print(f"   期望血糖下降范围: {self.delta_threshold_min} - {self.delta_threshold_max} mmol/L")

            if sg_before_next_meal_val < self.hypoglycemia_threshold:
                reason_final = f"{reason_description}，{sg_before_next_meal_name}血糖低于{self.hypoglycemia_threshold}mmol/L，建议减少基础率{self.max_adjustment*100}%"
                print(f"{Fore.GREEN}   触发调整: {reason_final}{Style.RESET_ALL}")
                self.basal_adjustments[period_key] = 1.0 - self.max_adjustment
                self.adjustment_reasons[period_key] = reason_final
                adjustment_made = True
            elif diff < -self.delta_threshold_max: # 血糖下降过多，注意diff是负数
                reason_final = f"{reason_description}，血糖下降值({abs(diff):.2f})超过最大阈值{self.delta_threshold_max}mmol/L，建议减少基础率{self.max_adjustment*100}%"
                print(f"{Fore.GREEN}   触发调整: {reason_final}{Style.RESET_ALL}")
                self.basal_adjustments[period_key] = 1.0 - self.max_adjustment
                self.adjustment_reasons[period_key] = reason_final
                adjustment_made = True
            elif diff >= 0 or abs(diff) < self.delta_threshold_min : # 血糖未下降或下降不足
                detail_reason_suffix = "血糖未下降" if diff >=0 else f"血糖下降不足(未达到{self.delta_threshold_min}mmol/L)"
                reason_final = f"{reason_description}，{detail_reason_suffix}，建议增加基础率{self.max_adjustment*100}%"
                print(f"{Fore.GREEN}   触发调整: {reason_final}{Style.RESET_ALL}")
                self.basal_adjustments[period_key] = 1.0 + self.max_adjustment
                self.adjustment_reasons[period_key] = reason_final
                adjustment_made = True

            if not adjustment_made:
                # 如果执行到这里，意味着所有调整条件都不满足
                reason_final = f"{reason_description}，血糖变化在理想范围内，无需调整。"
                print(f"{Fore.YELLOW}   未触发调整: {reason_final}{Style.RESET_ALL}")
                self.adjustment_reasons[period_key] = reason_final # 即使未调整，也记录详细原因
        else:
            missing_sg_after = sg_after_meal_name if sg_after_meal_val is None else ""
            missing_sg_before_next = sg_before_next_meal_name if sg_before_next_meal_val is None else ""
            conjunction = "和" if missing_sg_after and missing_sg_before_next else ""
            reason_description = f"缺少 {missing_sg_after}{conjunction}{missing_sg_before_next} 数据，无法评估，无需调整。"
            print(f"{Fore.RED}   {reason_description}{Style.RESET_ALL}")
            self.adjustment_reasons[period_key] = reason_description # 记录数据缺失的原因


def get_basal_recommendations(patient_number, date=None):
    """
    获取患者的基础率调整建议
    
    参数：
    patient_number: 患者编号
    date: 指定日期，如果为None则使用当天
    
    返回：
    JSON格式的基础率调整建议
    """
    try:
        print(f"\n{Fore.BLUE}=============================================")
        print(f"开始计算患者 {patient_number} 的基础率调整建议")
        print(f"============================================={Style.RESET_ALL}")
        
        # 处理日期
        current_date = datetime.now().date()
        if date is None:
            date = current_date
            print(f"使用当前日期: {date}")
        elif isinstance(date, str):
            date = datetime.strptime(date, "%Y-%m-%d").date()
            print(f"使用指定日期: {date}")
        
        # 检查如果日期是未来日期，则返回空的建议列表
        if date > current_date:
            print(f"{Fore.YELLOW}未来日期 {date}，返回空建议列表{Style.RESET_ALL}")
            return {
                "patient_number": patient_number,
                "date": str(date),
                "recommendations": []
            }
        
        # 检查患者是否存在
        with connection.cursor() as cursor:
            # 在MySQL中使用%s占位符代替命名占位符
            query = """
                SELECT COUNT(*) FROM patient_info WHERE patient_number = %s
            """
            cursor.execute(query, [patient_number])
            
            exists = cursor.fetchone()[0] > 0
            
            if not exists:
                print(f"{Fore.RED}患者 {patient_number} 不存在，返回空建议列表{Style.RESET_ALL}")
                return {
                    "patient_number": patient_number,
                    "date": str(date),
                    "recommendations": []
                }
            
            # 检查患者CGM数据表是否存在 (MySQL兼容方式)
            try:
                # 尝试查询表，如果不存在会抛出异常
                table_name = f"cgm_{patient_number}"
                # 将表名与SQL语句直接拼接，但不在此使用参数
                query = f"SELECT 1 FROM {table_name} LIMIT 1"
                cursor.execute(query)
                table_exists = True
            except Exception as e:
                print(f"{Fore.RED}患者 {patient_number} 的CGM数据表不存在: {e}{Style.RESET_ALL}")
                table_exists = False
            
            if not table_exists:
                print(f"{Fore.RED}患者 {patient_number} 的CGM数据表不存在，返回空建议列表{Style.RESET_ALL}")
                return {
                    "patient_number": patient_number,
                    "date": str(date),
                    "recommendations": []
                }
            
            # 检查指定日期是否有足够的CGM数据
            start_date = datetime.combine(date, time(0, 0))
            end_date = datetime.combine(date, time(23, 59, 59))
            
            # 将表名与SQL语句直接拼接，参数通过列表传递
            table_name = f"cgm_{patient_number}"
            query = f"""
                SELECT COUNT(*) FROM {table_name}
                WHERE sg_date BETWEEN %s AND %s
            """
            cursor.execute(query, [start_date, end_date])
            
            data_count = cursor.fetchone()[0]
            
            if data_count < 10:  # 假设至少需要10个数据点
                print(f"{Fore.YELLOW}患者 {patient_number} 在 {date} 的CGM数据不足 (仅有 {data_count} 条记录)，可能影响调整建议精度{Style.RESET_ALL}")
        
        # 创建基础率调整对象
        basal_adjuster = BasalRateAdjustment(patient_number)
        
        # 生成基础率调整建议
        recommendations = basal_adjuster.generate_basal_recommendations(date)
        
        # 检查是否有产生实际调整
        has_adjustment = any(rec["adjustment_pct"] != 0 for rec in recommendations)
        if not has_adjustment:
            print(f"\n{Fore.YELLOW}警告: 所有时间段都未触发调整条件，可能是因为:{Style.RESET_ALL}")
            print(f"  1. CGM数据不完整或不连续")
            print(f"  2. 血糖差值未超过调整阈值 (±{basal_adjuster.delta_threshold_min} mmol/L)")
            print(f"  3. 白天血糖变化在理想范围内")
        
        # 格式化结果
        result = {
            "patient_number": patient_number,
            "date": str(date),
            "recommendations": recommendations
        }
        
        print(f"\n{Fore.BLUE}基础率调整建议计算完成{Style.RESET_ALL}")
        return result
    except Exception as e:
        print(f"{Fore.RED}生成基础率建议出错: {e}{Style.RESET_ALL}")
        import traceback
        traceback.print_exc()
        return {
            "patient_number": patient_number,
            "date": str(date) if date else str(datetime.now().date()),
            "error": str(e),
            "recommendations": []
        } 